/*
 * TuringMachine.cpp
 *
 *  Created on: Jun 17, 2011
 *      Author: mmerchan
 */


#include "TuringMachine.h"
#include "StateAction.h"

using namespace std;


TuringMachine::TuringMachine(char * initial) {
	addState(initial);
	this->actualState = getState(initial);
}

vector<int>* TuringMachine::process(const vector<int>* finiteTapeIn) {
	map<int, int> tape;
	vector<int>* finiteTapeOut= new vector<int>();
	tapeIndex=0;
	int tapeMaxIndex=0;
	int tapeMinIndex=0;

	int i = 0;
	for (i = 0; i < finiteTapeIn->size(); i++)
		tape[i] = (*finiteTapeIn)[i];

	while(nextStep(&tape)){
		tapeMaxIndex=tapeMaxIndex<tapeIndex?tapeIndex:tapeMaxIndex;
		tapeMinIndex=tapeMinIndex>tapeIndex?tapeIndex:tapeMinIndex;
	}

	for(i = tapeMinIndex ; i <= tapeMaxIndex ; i++){
		(*finiteTapeOut).push_back(tape[i]);
	}
	
	return finiteTapeOut;
}

bool TuringMachine::nextStep(map<int, int> * tape) {
	// std::map returns 0 if element doesn't exist
	int element = (*tape)[tapeIndex];

	if (actualState == NULL)
		return false;

	Arc * arc = actualState->getArc(element);

	// NULL Arc means the iteration is over and the machine finished
	if (arc != NULL) {

		StateAction * action = arc->getAction();
		if (action->isMovement()) {
			StateAction::MovementType type = action->getMovementType();
			tapeIndex += (type == StateAction::LEFT) ? -1 : 1;
		} else {
			int value = action->getValue();
			(*tape)[tapeIndex] = value;
		}

		if (arc->getNext() != NULL) {
			actualState = arc->getNext();
			return true;
		}
	}
	return false;
}

bool TuringMachine::hasState(string name){
	return getState(name)!=NULL;
}

void TuringMachine::addState(char * name) {
	if(!hasState(name))
		states.push_back(new State(string(name)));
}

TuringMachine::State * TuringMachine::getState(string name) {
	list<State *>::iterator itr;
	for (itr = states.begin(); itr != states.end(); itr++)
		if ((*itr)->getName() == name)
			return (*itr);
	return NULL;
}



void TuringMachine::addStateAction(char * from, char * to, int input, StateAction * action){
	getState(from)->addAction(getState(string(to)), input, action);
}

list<TuringMachine::State *>& TuringMachine::getStateList() {
	return states;
}

	
string TuringMachine::toString(){
	string s= "";
	list<State *>::iterator itr;
	for (itr = states.begin(); itr != states.end(); itr++)
		for(int i=0;i<3;i++)
			if((*itr)->getArc(i)!=NULL)
				s+=string((*itr)->getName())+ "," + string(1,'0'+i) + "," + string((*itr)->getArc(i)->getNext()->getName()) + "," + (*itr)->getArc(i)->getAction()->toString() + "\n";
	return s;

}
